{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# python notebook for Make Your Own Neural Network\n",
    "# code for a 3-layer neural network, and code for learning the MNIST dataset\n",
    "# this version trains using the MNIST dataset, then tests on our own images\n",
    "# (c) Tariq Rashid, 2016\n",
    "# license is GPLv2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy\n",
    "# scipy.special for the sigmoid function expit()\n",
    "import scipy.special\n",
    "# library for plotting arrays\n",
    "import matplotlib.pyplot"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# helper to load data from PNG image files\n",
    "import imageio.v3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# neural network class definition\n",
    "class neuralNetwork:\n",
    "    \n",
    "    \n",
    "    # initialise the neural network\n",
    "    def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate):\n",
    "        # set number of nodes in each input, hidden, output layer\n",
    "        self.inodes = inputnodes\n",
    "        self.hnodes = hiddennodes\n",
    "        self.onodes = outputnodes\n",
    "        \n",
    "        # link weight matrices, wih and who\n",
    "        # weights inside the arrays are w_i_j, where link is from node i to node j in the next layer\n",
    "        # w11 w21\n",
    "        # w12 w22 etc \n",
    "        self.wih = numpy.random.normal(0.0, pow(self.inodes, -0.5), (self.hnodes, self.inodes))\n",
    "        self.who = numpy.random.normal(0.0, pow(self.hnodes, -0.5), (self.onodes, self.hnodes))\n",
    "\n",
    "        # learning rate\n",
    "        self.lr = learningrate\n",
    "        \n",
    "        # activation function is the sigmoid function\n",
    "        self.activation_function = lambda x: scipy.special.expit(x)\n",
    "        \n",
    "        pass\n",
    "\n",
    "    \n",
    "    # train the neural network\n",
    "    def train(self, inputs_list, targets_list):\n",
    "        # convert inputs list to 2d array\n",
    "        inputs = numpy.array(inputs_list, ndmin=2).T\n",
    "        targets = numpy.array(targets_list, ndmin=2).T\n",
    "        \n",
    "        # calculate signals into hidden layer\n",
    "        hidden_inputs = numpy.dot(self.wih, inputs)\n",
    "        # calculate the signals emerging from hidden layer\n",
    "        hidden_outputs = self.activation_function(hidden_inputs)\n",
    "        \n",
    "        # calculate signals into final output layer\n",
    "        final_inputs = numpy.dot(self.who, hidden_outputs)\n",
    "        # calculate the signals emerging from final output layer\n",
    "        final_outputs = self.activation_function(final_inputs)\n",
    "        \n",
    "        # output layer error is the (target - actual)\n",
    "        output_errors = targets - final_outputs\n",
    "        # hidden layer error is the output_errors, split by weights, recombined at hidden nodes\n",
    "        hidden_errors = numpy.dot(self.who.T, output_errors) \n",
    "        \n",
    "        # update the weights for the links between the hidden and output layers\n",
    "        self.who += self.lr * numpy.dot((output_errors * final_outputs * (1.0 - final_outputs)), numpy.transpose(hidden_outputs))\n",
    "        \n",
    "        # update the weights for the links between the input and hidden layers\n",
    "        self.wih += self.lr * numpy.dot((hidden_errors * hidden_outputs * (1.0 - hidden_outputs)), numpy.transpose(inputs))\n",
    "        \n",
    "        pass\n",
    "\n",
    "    \n",
    "    # query the neural network\n",
    "    def query(self, inputs_list):\n",
    "        # convert inputs list to 2d array\n",
    "        inputs = numpy.array(inputs_list, ndmin=2).T\n",
    "        \n",
    "        # calculate signals into hidden layer\n",
    "        hidden_inputs = numpy.dot(self.wih, inputs)\n",
    "        # calculate the signals emerging from hidden layer\n",
    "        hidden_outputs = self.activation_function(hidden_inputs)\n",
    "        \n",
    "        # calculate signals into final output layer\n",
    "        final_inputs = numpy.dot(self.who, hidden_outputs)\n",
    "        # calculate the signals emerging from final output layer\n",
    "        final_outputs = self.activation_function(final_inputs)\n",
    "        \n",
    "        return final_outputs"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# number of input, hidden and output nodes\n",
    "input_nodes = 784\n",
    "hidden_nodes = 200\n",
    "output_nodes = 10\n",
    "\n",
    "# learning rate\n",
    "learning_rate = 0.1\n",
    "\n",
    "# create instance of neural network\n",
    "n = neuralNetwork(input_nodes,hidden_nodes,output_nodes, learning_rate)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "# load the mnist training data CSV file into a list\n",
    "training_data_file = open(\"mnist_dataset/mnist_train.csv\", 'r')\n",
    "training_data_list = training_data_file.readlines()\n",
    "training_data_file.close()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "# train the neural network\n",
    "\n",
    "# epochs is the number of times the training data set is used for training\n",
    "epochs = 10\n",
    "\n",
    "for e in range(epochs):\n",
    "    # go through all records in the training data set\n",
    "    for record in training_data_list:\n",
    "        # split the record by the ',' commas\n",
    "        all_values = record.split(',')\n",
    "        # scale and shift the inputs\n",
    "        inputs = (numpy.asfarray(all_values[1:]) / 255.0 * 0.99) + 0.01\n",
    "        # create the target output values (all 0.01, except the desired label which is 0.99)\n",
    "        targets = numpy.zeros(output_nodes) + 0.01\n",
    "        # all_values[0] is the target label for this record\n",
    "        targets[int(all_values[0])] = 0.99\n",
    "        n.train(inputs, targets)\n",
    "        pass\n",
    "    pass"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "test with our own image "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "loading ... my_own_images/2828_my_own_image.png\n",
      "min =  0.01\n",
      "max =  1.0\n",
      "[[0.01128895]\n",
      " [0.0286039 ]\n",
      " [0.02139342]\n",
      " [0.77091725]\n",
      " [0.01032456]\n",
      " [0.00902259]\n",
      " [0.02485261]\n",
      " [0.02019078]\n",
      " [0.17644227]\n",
      " [0.11097788]]\n",
      "network says  3\n"
     ]
    },
    {
     "data": {
      "image/png": "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vdpz5sknn4xqW70RZ0AAABMUEADABAUEADBBAQEATFBAAAATFBAAwAQFBAAwQQEBAExQQAAAExQQAMAEBQQAMEEBAQBMUEAAABPcmjjBVFRUeM50dHREta2BAwdGlQMuxtChQ7tsW59//nmXbas34gwIAGCCAgIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJCggAYIICAgCYoIAAACYoIACACW5GmmD69+9vPQJwwY4fP+45c++998Zhks4VFRV12bZ6I86AAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJCggAYIICAgCYoIAAACYoIACACQoIAGCCAgIAmOBmpABioq2tzXNm5syZnjP//Oc/PWfmzp3rOSNJM2bMiCqHC8MZEADABAUEADDhuYC2bNmim2++WdnZ2fL5fNqwYUPE8845Pf7448rKytKAAQNUWFioPXv2xGpeAECC8FxALS0tysvLU3l5eafPL1++XM8//7xefPFFbdu2TZdeeqmKioqi+uApAEDi8nwRQnFxsYqLizt9zjmn5557To8++qhuueUWSdLq1auVkZGhDRs2aPbs2Rc3LQAgYcT0PaD6+no1NjaqsLAw/FggEFB+fr6qq6s7zbS2tioUCkUsAIDEF9MCamxslCRlZGREPJ6RkRF+7uvKysoUCATCS05OTixHAgB0U+ZXwZWWlioYDIaXhoYG65EAAF0gpgWUmZkpSWpqaop4vKmpKfzc1/n9fqWkpEQsAIDEF9MCys3NVWZmpioqKsKPhUIhbdu2TQUFBbHcFACgh/N8FdzRo0e1d+/e8Nf19fXauXOn0tLSNHToUC1evFhPPvmkrrrqKuXm5uqxxx5Tdna2pk+fHsu5AQA9nOcC2r59u2688cbw10uWLJEkzZkzR6tWrdJDDz2klpYWzZ8/X0eOHNF1112nzZs3q3///rGbGgDQ4/mcc856iNOFQiEFAgEFg0HeDwJO09HR4TnT2toa1bZ2797tOfOzn/3Mc2br1q2eM6f/mseFevvttz1nJPEP5yhd6Ou4+VVwAIDeiQICAJiggAAAJiggAIAJCggAYIICAgCYoIAAACYoIACACQoIAGCCAgIAmKCAAAAmKCAAgAkKCABgwvPHMQA9QXt7e1S5P/3pT54za9eu9Zypr6/3nDlw4IDnzJdffuk5I0lddZP8WbNm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GKYkufXr14e/7ujocJmZme6ZZ54JP3bkyBHn9/vd2rVrDSbsGl/fD845N2fOHHfLLbeYzGPl0KFDTpKrqqpyzp38u+/bt69bt25deJ1///vfTpKrrq62GjPuvr4fnHPuBz/4gfv5z39uN9QF6PZnQG1tbaqpqVFhYWH4sT59+qiwsFDV1dWGk9nYs2ePsrOzNXz4cN11113at2+f9Uim6uvr1djYGHF8BAIB5efn98rjo7KyUoMHD9aoUaO0cOFCHT582HqkuAoGg5KktLQ0SVJNTY3a29sjjofRo0dr6NChCX08fH0/nPLaa68pPT1dY8eOVWlpqY4dO2Yx3ll1u5uRft0XX3yhEydOKCMjI+LxjIwMffLJJ0ZT2cjPz9eqVas0atQoHTx4UMuWLdP111+v3bt3Kzk52Xo8E42NjZLU6fFx6rneYtq0aZo5c6Zyc3NVV1enRx55RMXFxaqurlZSUpL1eDHX0dGhxYsXa9KkSRo7dqykk8dDv379lJqaGrFuIh8Pne0HSbrzzjs1bNgwZWdna9euXXr44YdVW1urt956y3DaSN2+gPA/xcXF4T+PHz9e+fn5GjZsmN58803dc889hpOhO5g9e3b4z+PGjdP48eM1YsQIVVZWasqUKYaTxUdJSYl2797dK94HPZez7Yf58+eH/zxu3DhlZWVpypQpqqur04gRI7p6zE51+x/BpaenKykp6YyrWJqampSZmWk0VfeQmpqqkSNHau/evdajmDl1DHB8nGn48OFKT09PyONj0aJF2rRpkz744IOIj2/JzMxUW1ubjhw5ErF+oh4PZ9sPncnPz5ekbnU8dPsC6tevnyZMmKCKiorwYx0dHaqoqFBBQYHhZPaOHj2quro6ZWVlWY9iJjc3V5mZmRHHRygU0rZt23r98bF//34dPnw4oY4P55wWLVqk9evX6/3331dubm7E8xMmTFDfvn0jjofa2lrt27cvoY6H8+2HzuzcuVOSutfxYH0VxIV4/fXXnd/vd6tWrXL/+te/3Pz5811qaqprbGy0Hq1LPfDAA66ystLV19e7jz76yBUWFrr09HR36NAh69Hiqrm52e3YscPt2LHDSXIrVqxwO3bscJ999plzzrmnnnrKpaamuo0bN7pdu3a5W265xeXm5rqvvvrKePLYOtd+aG5udg8++KCrrq529fX17r333nPf/e533VVXXeWOHz9uPXrMLFy40AUCAVdZWekOHjwYXo4dOxZeZ8GCBW7o0KHu/fffd9u3b3cFBQWuoKDAcOrYO99+2Lt3r/vVr37ltm/f7urr693GjRvd8OHD3eTJk40nj9QjCsg551544QU3dOhQ169fPzdx4kS3detW65G63O233+6ysrJcv3793De+8Q13++23u71791qPFXcffPCBk3TGMmfOHOfcyUuxH3vsMZeRkeH8fr+bMmWKq62ttR06Ds61H44dO+amTp3qBg0a5Pr27euGDRvm5s2bl3D/SOvsv1+Se+WVV8LrfPXVV+6nP/2pu/zyy93AgQPdjBkz3MGDB+2GjoPz7Yd9+/a5yZMnu7S0NOf3+92VV17pfvGLX7hgMGg7+NfwcQwAABPd/j0gAEBiooAAACYoIACACQoIAGCCAgIAmKCAAAAmKCAAgAkKCABgggICAJiggAAAJiggAIAJCggAYOL/AfrUd569X6PPAAAAAElFTkSuQmCC",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# test the neural network with our own images\n",
    "\n",
    "# load image data from png files into an array\n",
    "print (\"loading ... my_own_images/2828_my_own_image.png\")\n",
    "img_array = imageio.v3.imread('my_own_images/2828_my_own_image.png', mode='F')\n",
    "    \n",
    "# reshape from 28x28 to list of 784 values, invert values\n",
    "img_data  = 255.0 - img_array.reshape(784)\n",
    "    \n",
    "# then scale data to range from 0.01 to 1.0\n",
    "img_data = (img_data / 255.0 * 0.99) + 0.01\n",
    "print(\"min = \", numpy.min(img_data))\n",
    "print(\"max = \", numpy.max(img_data))\n",
    "\n",
    "# plot image\n",
    "matplotlib.pyplot.imshow(img_data.reshape(28,28), cmap='Greys', interpolation='None')\n",
    "\n",
    "# query the network\n",
    "outputs = n.query(img_data)\n",
    "print (outputs)\n",
    "\n",
    "# the index of the highest value corresponds to the label\n",
    "label = numpy.argmax(outputs)\n",
    "print(\"network says \", label)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
